﻿using UnityEngine;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

// goes through the entire group's tracklist starting from one location and finds all singly contained groups, then returns them all

//
static class TrackIterator
{
    /*  returns an array of Track lists that correspond to all individual and non-connected paths along the track
     *  parameters:
     *      original : The original TrackGroup that is going to be looked through
     *      references: The neighboring Track pieces of the one that was remove just before this is called
     */


    // Currently in an infinite loop. Fix on Friday
    // UPDATE ON PROGRESS: Finished, needs refinement later; decently fast currently
    // RE: UPDATE -- Not quite finished, not recognizing that the number of members is changing in each group
    // RE: RE: UPDAte -- Seems to work fine for now
    // STATUS UPDATE: Needs to be revised to work entirely with HashSets instead of Lists. Hopefully will not need any more changes than that
    static public HashSet<Track>[] findBrokenPaths(TrackGroup original, Track[] references)
    {
        HashSet<HashSet<Track>> finalList = new HashSet<HashSet<Track>>();
        HashSet<Track> skip = new HashSet<Track>(); // holds a skip list to make sure that the same path isn't iterate over more than once
        
        int numSubLists = -1;

        int numIt;
        int MaxIt = 30;

        // start with one reference and continue until the last reference has been checked
        foreach (Track worker in references)
        {
            numIt = 0;
            // if skippable list isn't empty, check to see if current worker is in it
            if (skip.Count > 0)
            {
                if (skip.Contains(worker)){
                    continue;
                }
            }
            // populate open list
            HashSet<Track> open = new HashSet<Track>();
            Track[] n_List = worker.getNeighbors(); // changed to Track[] n_List from int[] n_List to solve type error
            foreach(Track n in n_List){ // TODO need to redo this foreach loop probably, changed type from "int n in n_List" to "Track n in n_List"
                open.Add (n);
				//open.Add(original.getTrackByID(n.ID)); // changed from .getTrackByID(n) to .getTrackByID(n.ID) :: temporary measure until IDs are done away with
            } // we can probably assume that since we are only dealing with one list for the moment all neighbors are in the same list. Thus this can be changed to just
			// open.Add(n);

            // initialize closed list to just the worker
            HashSet<Track> closed = new HashSet<Track>();
            closed.Add(worker);

            // now iterate through the now populated open list for as long as there are pieces within the open list
            bool end = false;

            while (!end){ // end will == true when open list has no objects within
                // get new options for open list from neighbors of current open list
                HashSet<Track> addList = new HashSet<Track>();
                foreach(Track o in open){
                    if (o != null)
                    {
                        n_List = o.getNeighbors();
                        foreach (Track n in n_List)
                        {
                            //addList.Add(original.getTrackByID(n));
							if (original.contains(n)){
								addList.Add (n);
							}
                        }
                    }
                }
                // send all open Tracks to the remove list
                HashSet<Track> removeList = new HashSet<Track>();
                foreach(Track o in open){
                    removeList.Add(o);
                }
                // now remove
                foreach(Track r in removeList){
                    open.Remove(r);
                    closed.Add(r);
                }
                // clear remove
                removeList.Clear();

                // add the new options from add to open list
                foreach(Track a in addList){
                    open.Add(a);
                }
                // clear add
                addList.Clear();
                
                // check to see if current open list contains a reference Track
                foreach(Track r in references){
                    if (open.Contains(r)){
                        skip.Add(r);
                    }
                }

                // now make sure that if closed has an item then it cannot be in open
                foreach (Track c in closed)
                {
                    if (open.Contains(c))
                    {
                        open.Remove(c);
                    }
                }

                // now finally check to see if there are no Tracks in the open list
                if (open.Count == 0)
                {
                    end = true;
                }
                numIt++;

                if (numIt >= MaxIt)
                {
                    end = true;
                }
                
                /* Debug code, not really necesary right now
                printList(closed, "Closed");
                printList(open, "Open");
                printList(remove, "Remove");
                printList(add, "Add");
                Console.WriteLine("Size of Open = {0}", open.Count);
                
                Console.ReadKey();
                Console.Clear();
                 */
            }

            numSubLists++;
            finalList.Add(new HashSet<Track>());

            foreach (Track c in closed)
            {
                finalList.ElementAt(numSubLists).Add(c);
            }

        }
        if (numSubLists >= 0){
            return finalList.ToArray();
        }
        return null; // worst case scenario, should not happen!
    }

    static private void printList(List<Track> list, string name)
    {
        Console.WriteLine("{0}", name);

        foreach (Track T in list)
        {
            Console.WriteLine("\tTrack[{0}] is in list", T.ID);
        }

        
    }
    
}
